import json

from django.shortcuts import render
from django.views.generic import View
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
import re
from django.conf import settings
from users.models import User
from django import db
from celery_tasks import tasks_list
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired
from django.contrib.auth import authenticate, login, logout
from utils.views import LoginRequiredMixin
from users.models import Address
from django_redis import get_redis_connection
from goods.models import GoodsSKU
# Create your views here.
# def register(request):
#     # 返回注册页面
#     return render(request, 'register.html')

class UserInfoView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """查询用户信息和地址信息"""
        # 从request中获取user对象
        user = request.user

        try:
            # 查询用户地址，选最新的一个
            address = user.address_set.latest('create_time')
        except Address.DoesNotExist:
            address = None

        # 将浏览记录保存至redis，此处从redis查询
        # 创建redis链接对象
        redis_conn = get_redis_connection('default')
        # 采用list，合理的压入提出顺序完美符合浏览记录的展示特征
        # 展示五条
        sku_ids = redis_conn.lrange('history_%s' % user.id, 0, 4)
        # 记录sku模型对象的列表
        sku_list = []
        # 遍历sku——ids取出id
        for sku_id in sku_ids:
            sku = GoodsSKU.objects.get(id=sku_id)
            sku_list.append(sku)

        # 构造上下文
        context = {
            'address': address,
            'sku_list': sku_list,
        }

        return render(request, 'user_center_info.html', context)



class AddressView(LoginRequiredMixin, View):
    """用户地址"""

    def get(self, request):
        """提供用户地址页面"""
        # 从request中获取user
        user = request.user
        try:
            # 查询用户地址，选择最新加入的地址
            # address = Address.objects.filter(user=user).order_by('-create_time')[0]
            # address = user.address_set.order_by('-create_time')[0]
            address = user.address_set.latest('create_time')
        except Address.DoesNotExist:
            # 如果地址信息不存在
            address = None

        # 构造上下文
        context = {
            # request中自带user，调用模板时， request会传给模板
            # ‘user’：user，    # 不用单独写出来
            'address': address
        }
        return render(request, 'user_center_site.html', context)

    def post(self, request):
        """修改地址信息"""

        # 接收地址表单数据
        user = request.user
        recv_name = request.POST.get('recv_name')
        addr = request.POST.get('addr')
        zip_code = request.POST.get('zip_code')
        recv_mobile = request.POST.get('recv_mobile')

        # 参数检验
        if all([recv_name, addr, zip_code, recv_mobile]):
            Address.objects.create(
                user=user,
                receiver_mobile=recv_mobile,
                receiver_name=recv_name,
                detail_addr=addr,
                zip_code=zip_code
            )
        # 自动进行登陆校验，及时展示刚刚添加的地址信息
        return redirect(reverse("users:address"))


class LogoutView(View):
    """退出登陆"""

    def get(self, request):
        """处理退出登陆逻辑"""
        # 由Django用户认证系统完成， 需要清理cookie和session，request中由user信息
        logout(request)
        # 退出后跳转到主页
        return redirect(reverse('goods:index'))


class LoginView(View):
    """登陆"""

    def get(self, request):
        """响应登陆界面"""
        return render(request, 'login.html')

    def post(self, request):
        """处理登陆逻辑"""
        # 获取用户名和密码
        user_name = request.POST.get('username')
        password = request.POST.get('pwd')

        # 参数校验
        if not all([user_name, password]):
            return redirect(reverse('users:login'))

        # django用户认证系统判断是否登陆成功
        user = authenticate(username=user_name, password=password)

        # 验证登陆失败
        if user is None:
            # f返回登陆页面， 提示用户名或密码错误
            return render(request, 'login.html', {'errmsg':'用户名或密码错误'})

        # 验证登陆成功，并判断是否是激活用户
        if user.is_active is False:
            # 如果不是激活用户
            return render(request, 'login.html', {'errmsg':'用户未激活'})

        # 登陆，session中保存用户登陆状态
        login(request, user)

        # 是否勾选‘记住用户名
        remembered = request.POST.get('remembered')

        if remembered != 'on':
            # 没有勾选，不需要记住cookie信息，浏览器回话结束过期
            request.session.set_expiry(0)
        else:
            # 勾选， 需要记住cookie信息，10天 后过期
            request.session.set_expiry(60*60*24*10)

        # 如果未登陆之前购物车中有数据，登陆之后将购物车中的数据合并到redis
        # 并清空在cookie中存在的购物车数据
        cart_json = request.COOKIES.get('cart')
        redis_conn = get_redis_connection('default')
        user_id = user.id
        if cart_json:
            cart_dict_cookie = json.loads(cart_json)
        else:
            cart_dict_cookie = {}
        # 将数据与redis中的数据合并
        cart_dict_redis = redis_conn.hgetall('cart_%s' % user_id)

        for sku_id, count in cart_dict_cookie.items():
            # 由于redis中的键和值是bytes，cookie中是字符串，要注意转化类型
            sku_id = sku_id.encode()
            if sku_id in cart_dict_redis:
                # 累加到redis
                origin_count = cart_dict_redis[sku_id]
                count += int(origin_count)
                # 如果cookie中的商品在redis中有，就累加后的赋值，没有的话直接添加
            cart_dict_redis[sku_id] = count
        # 将合并后的数据写入redis，注意hmset不能写入空字典
        if cart_dict_redis:
            redis_conn.hmset('cart_%s' % user_id, cart_dict_redis)

        # 获取next参数，用于判断登陆界面从哪里来的
        next = request.GET.get('next')
        if next is None:
            # 跳转到首页
            response = redirect(reverse('goods:index'))
        else:
            # 如果重定向到place页面，只能接收post请求，而next是get请求
            # 所以要区别对待, 重定向到购物车
            if next == '/orders/place':
                response = redirect('/cart')
            else:
                response = redirect(next)
        response.delete_cookie('cart')
        return response



class ActiveView(View):
    """邮件激活"""

    def get(self, request, token):
        """处理激活请求"""

        # 创建序列化器
        serializer = Serializer(settings.SECRET_KEY, 3600)

        try:
            # 使用序列化器，获取token明文信息， 需要判断签名是否过期
            result = serializer.loads(token)
        except SignatureExpired:
            # 提示激活链接已经过期
            return HttpResponse('激活链接已经过期')

        # 获取用户id
        user_id = result.get('confirm')
        try:
            # 查询需要激活的用户手不是存在
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            # 提示用户不存在
            return HttpResponse('用户不存在')

        # 设置激活用户的is_active为True
        user.is_active = True
        user.save()
        # 相应信息给客户端
        return redirect(reverse('users:login'))


class RegisterView(View):
    """类视图：处理注册"""

    def get(self, request):
        """处理GET请求，返回注册页面"""
        return render(request, 'register.html')

    def post(self, request):
        """处理POST请求，实现逻辑注册"""
        # 获取注册请求参数
        user_name = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        allow = request.POST.get('allow')

        # 参数校验， 缺少任意一个参数，就不要继续执行
        if not all([user_name, password, email]):
            return redirect(reverse('users:register'))

        # 判断邮箱
        if not re.match(r"^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", email):
            return render(request, 'register.html', {'errmsg':'邮箱格式错误'})

        # 判断是否勾选协议
        if allow != 'on':
            return render(request, 'register.html', {'errmsg':'没有勾选协议'})

        # 保存数据到数据库
        try:
            # 隐私信息需要加密，可以直接使用django提供的用户认真系统完成
            user = User.objects.create_user(user_name, email, password)
        except db.IntegrityError:
            return render(request, 'register.html', {'errmsg': '用户已注册'})
        user.is_active = False
        # 保存数据到数据库
        user.save()
        # 生成激活token

        token = user.generate_active_token()

        # Django发送激活邮件，阻塞，影响结果
        tasks_list.send_active_email.delay(email, user_name, token)

        return redirect(reverse('users:login'))




